# -*- coding: utf-8 -*-
# @Time     : 2023/11/22 13:55
# @Author   : Long-Long Qiu
# @FileName : packing_server_pack.py
# @Product  : PyCharm
# import packages
import copy
import os
import random
from flask import Flask, request, send_file
from flask_cors import CORS
import json
import time
import hashlib
import matplotlib
import base64
import test2
import pickle
import pandas as pd
import argparse
import math
import openpyxl
from openpyxl.styles import Alignment
from openpyxl import load_workbook
from openpyxl.drawing.image import Image
from datetime import timedelta
import threading
from py3dbp import Packer, Bin, Item, Painter
from io import BytesIO
import PIL

matplotlib.use('agg')

app = Flask(__name__)
CORS(app, supports_credentials=True, origins='*')  # 允许跨域请求
app.secret_key = 'abc123'
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './session'
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)  # 设置cookie 的时间为7天

parser = argparse.ArgumentParser(description='启动Flask服务')


car_size_map = {
    '4.2': [4200, 1900, 2500],
    '6.8': [6800, 2400, 3000],
    '7.6': [7600, 2400, 3000],
    '9.6': [9600, 2400, 3000],
    '13.5': [13500, 2400, 3000],
    '17.5': [17500, 3000, 3000]
}

car_loadbear_map = {
    '4.2': 3 * 1000,
    '6.8': 10 * 1000,
    '7.6': 13 * 1000,
    '9.6': 18 * 1000,
    '13.5': 30 * 1000,
    '17.5': 35 * 1000
}

# 不同线路对应的车型
route_car_map = {
    '乌鲁木齐市-上海市': [{'size': '4.2', 'price': 16834}, {'size': '6.8', 'price': 30301},
                          {'size': '7.6', 'price': 30862}, {'size': '9.6', 'price': 34229},
                          {'size': '13.5', 'price': 44891}, {'size': '17.5', 'price': 50502}],
    '宁波市-武汉市': [{'size': '4.2', 'price': 3709}, {'size': '6.8', 'price': 3826}, {'size': '7.6', 'price': 5166},
                      {'size': '9.6', 'price': 7174}, {'size': '13.5', 'price': 8160}, {'size': '17.5', 'price': 9087}],
    '宁波市-襄阳市': [{'size': '4.2', 'price': 4689}, {'size': '6.8', 'price': 4851}, {'size': '7.6', 'price': 6510},
                      {'size': '9.6', 'price': 9063}, {'size': '13.5', 'price': 10270},
                      {'size': '17.5', 'price': 11360}],
    '武汉市-葛店开发区': [{'size': '4.2', 'price': 200}, {'size': '6.8', 'price': 350}, {'size': '7.6', 'price': 380},
                          {'size': '9.6', 'price': 480}, {'size': '13.5', 'price': 1750},
                          {'size': '17.5', 'price': 2000}],
    '焦作市-上海市': [{'size': '4.2', 'price': 3520}, {'size': '6.8', 'price': 4950}, {'size': '7.6', 'price': 4950},
                      {'size': '9.6', 'price': 6325}, {'size': '13.5', 'price': 9200},
                      {'size': '17.5', 'price': 10350}],
}


def md5_encode(text):
    """
    对文本进行md5加密
    """
    md5_hash = hashlib.md5()
    md5_hash.update(text.encode('utf-8'))
    encoded_text = md5_hash.hexdigest()
    return encoded_text


def image_to_base64(image_path):
    with open(image_path, "rb") as image_file:
        image_data = image_file.read()
        base64_data = base64.b64encode(image_data)
        base64_string = base64_data.decode("utf-8")
        return base64_string


def base64_to_image(bs64_str, image_path):
    image_data = base64.b64decode(bs64_str)
    with open(image_path, 'wb') as f:
        f.write(image_data)


def packing_items(params, token, user_ip='127.0.0.1', pre_packing_cubes=True, pre_min_num=20, top_num=5):
    preMinNum = pre_min_num
    topNum = top_num

    if not os.path.exists(f'./results/{token}.json'):
        with open(f'./results/{token}.json', 'w') as fp:
            json.dump([], fp)

    pack_start = time.time()
    matplotlib_time, plotly_time = 0., 0.

    prices = []

    # 1. 获取货物信息
    items = params.get('items', [])
    config_parameters = params.get('config_parameters', [])

    if sum([ie[4] for ie in items]) < pre_min_num:
        pre_packing_cubes = False

    print(items)

    if not items:
        return {
            'code': 101,
            'result': None,
            'description': '缺少货物参数'
        }
    # 2. 获取相关的参数
    radius1 = int(config_parameters['dish']['second_dish_radius_1']) / 100
    radius2 = int(config_parameters['dish']['second_dish_radius_2']) / 100
    all_cars = params['cars']
    print(all_cars)
    prices = [car['price'] for car in all_cars]
    cars = [(car['size'][0], car['size'][1], car['size'][2], car['loadbear'], car['price']) for car in all_cars]
    cars = sorted(cars, key=lambda x: x[4])

    ie_v, ie_w = 0, 0
    for ie in items:
        ie_w += ie[3] * ie[4]
        ie_v += ie[0] * ie[1] * ie[2] * ie[4]

    results = []
    # 3. 使用单个货车进行装箱
    suc_num = 0
    single_flags = []
    print("#" * 30)
    print('开始计算单车方案')
    print("#" * 30)
    for s in range(len(cars)):
        b = cars[s]
        box = Bin(f"car-{s}", (b[0], b[1], b[2]), b[3], 0, put_type=0, price=b[4])

        total_bin_v = box.getVolume()
        total_bin_w = box.max_weight
        if total_bin_v < ie_v or total_bin_w < ie_w:
            continue

        # 3.1 装箱
        heaps, pack_result = test2.packing([box], items, radius1, radius2, pre_packing_cubes=pre_packing_cubes)

        b = pack_result.bins[0]
        # 3.2 判断装箱是否成功
        if len(b.items) >= pack_result.total_items:
            suc_num += 1
            success = True
        else:
            success = False
        single_flags.append(success)

        bin_v = float(b.width) * float(b.height) * float(b.depth)
        space_ratio = ie_v / bin_v

        # 3.4 计算承重利用率
        weight_ratio = ie_w / float(b.max_weight)
        if weight_ratio > 1.0 or space_ratio > 1.0:
            success = False

        # 3.5 车辆类型信息
        car_type = f"car{s}-{[a / 1000 for a in cars[s][0:3]]}"

        # item_color = {}
        # for heap_name, layers in heaps.items():
        #     item_color[f"{'-'.join([str(im) for im in layers[0][0][:4]])}"] = layers[0][0][7]

        # 3.9 结果汇总
        if success:
            results.append({
                'status': success,
                'bin_type': [car_type],
                'bin_num': [1],
                'space_ratio': space_ratio,
                'box_weight': float(b.max_weight),
                'goods_weight': ie_w,
                'weight_ratio': weight_ratio,
                'price': prices[s],
                'goods_volume': ie_v,
                'bin_volume': float(b.width * b.height * b.depth),
                # 'color': item_color,
                'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                'car-num': 1
            })

            with open(f'./results/{token}.json', 'w') as fp:
                json.dump(results, fp)

    # 4. 使用多个货车进行装箱
    old_multi_box = []

    total_num = top_num
    try_num = 0
    while suc_num < total_num:
        multi_boxes = []

        if not old_multi_box:
            print("#" * 30)
            print(f'开始生成2车方案')
            print("#" * 30)
            # 两车装箱方案
            for x in range(len(cars)):
                b1 = cars[x]
                for y in range(x, len(cars)):
                    b2 = cars[y]
                    multi_boxes.append([b1, b2])
                    # multi_boxes.append([Bin(f"car-{x}", (b1[0], b1[1], b1[2]), b1[3], 0, put_type=0, price=b1[4]),
                    #                     Bin(f"car-{y}", (b2[0], b2[1], b2[2]), b2[3], 0, put_type=0, price=b2[4])])
        else:
            print("#" * 30)
            print(f'开始生成{len(old_multi_box[0]) + 1}车方案')
            print("#" * 30)
            # 多车装箱方案
            for old_boxes in old_multi_box:
                for z in range(len(cars)):
                    other = cars[z]
                    ob = []
                    # for be in old_boxes:
                    #     ob.append(Bin(be.partno, (be.width, be.height, be.depth), be.max_weight, 0, put_type=0, price=be.price))
                    # for m in range(len(old_boxes)):
                    #     old_boxes[m].clearBin()
                    multi_boxes.append(old_boxes + [other])
                    # multi_boxes.append(old_boxes + [Bin(f"car-{z}", (other[0], other[1], other[2]), other[3], 0, put_type=0, price=other[4])])
        # old_multi_box = copy.deepcopy(multi_boxes)
        old_multi_box = multi_boxes

        # 按照成本排序
        multi_boxes = sorted(multi_boxes, key=lambda x: sum([su[4] for su in x]))
        # multi_boxes = sorted(multi_boxes, key=lambda x: sum([su.price for su in x]))

        print("#" * 30)
        print(f'开始计算{len(multi_boxes[0])}车方案')
        print("#" * 30)
        for indx, box in enumerate(multi_boxes):

            if suc_num >= total_num:
                break

            total_bin_v = sum([be[0] * be[1] * be[2] for be in box])
            # total_bin_v = sum([float(be.getVolume()) for be in box])
            total_bin_w = sum([be[3] for be in box])
            # total_bin_w = sum([float(be.max_weight) for be in box])
            if total_bin_v < ie_v or total_bin_w < ie_w:
                continue

            print(try_num, suc_num, total_num, len(box))
            # 4.1 装箱
            heaps, pack_result = test2.packing(box, items, radius1, radius2, pre_packing_cubes=pre_packing_cubes)
            try_num += 1

            # 4.2 判断装箱是否成功
            if sum([len(ie.items) for ie in pack_result.bins]) == pack_result.total_items:
                success = True
                suc_num += 1
            else:
                success = False

            # 4.3 计算空间利用率
            # ie_v, ie_w = 0., 0.
            # bin_v, bin_w = 0., 0.
            price = sum([be.price for be in pack_result.bins])

            if ie_w / total_bin_w > 1 or ie_v / total_bin_v > 1:
                success = False

            if price in prices:
                if success:
                    suc_num -= 1
            else:
                prices.append(price)
                # 4.4 车辆类型
                bin_type, bin_num = [], []
                for bi in pack_result.bins:
                    bin_type.append(
                        f"car-{str([float(bi.width) / 1000, float(bi.height) / 1000, float(bi.depth) / 1000])}")
                    bin_num.append(1)

                if success:
                    results.append({
                        'status': success,
                        'bin_type': bin_type,
                        'bin_num': bin_num,
                        'space_ratio': ie_v / total_bin_v,
                        'box_weight': total_bin_w,
                        'goods_weight': ie_w,
                        'weight_ratio': ie_w / total_bin_w,
                        'price': price,
                        'goods_volume': ie_v,
                        'bin_volume': total_bin_v,
                        'color': {},
                        'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                        'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                        'car-num': len(box)
                    })

                    with open(f'./results/{token}.json', 'w') as fp:
                        json.dump(results, fp)

    pack_end = time.time()
    total_time = pack_end - pack_start
    print(
        f"装箱算法耗时{round(total_time - plotly_time - matplotlib_time, 3)}秒，matplotlib绘图耗时{round(matplotlib_time, 3)}秒，plotly绘图耗时{round(plotly_time, 3)}秒，总耗时{round(total_time, 3)}秒")
    results = list(filter(lambda x: x['status'], results))
    # return sorted(results, key=lambda x: x['price'])


def packing_items_3(params, token, user_ip='127.0.0.1', pre_packing_cubes=True, pre_min_num=20, top_num=5):
    start = time.time()
    # 1. 准备结果文件
    path_to_result = parser.parse_args().sessionPath
    if not os.path.exists(f'{path_to_result}/{token}.json'):
        with open(f'{path_to_result}/{token}.json', 'w') as fp:
            json.dump({
                'finished': False,
                'result': []
            }, fp)

    # 2. 获取货物、车辆等信息
    items = params.get('items', [])
    config_parameters = params.get('config_parameters', [])

    if sum([ie[4] for ie in items]) < pre_min_num:
        pre_packing_cubes = False
    # radius1 = int(config_parameters['dish']['second_dish_radius_1']) / 100
    # radius2 = int(config_parameters['dish']['second_dish_radius_2']) / 100
    radius1 = 500
    radius2 = 700
    all_cars = params['cars']
    cars = [(car['size'][0], car['size'][1], car['size'][2], car['loadbear'], car['price']) for car in all_cars]
    cars = sorted(cars, key=lambda x: x[4], reverse=True)

    ie_v, ie_w = 0, 0
    for ie in items:
        ie_w += ie[3] * ie[4]
        ie_v += ie[0] * ie[1] * ie[2] * ie[4]

    results = []
    # 3. 计算单车方案
    suc_num = 0
    for index, b in enumerate(cars):
        box = Bin(f"car-{index}", (b[0], b[1], b[2]), b[3], 0, put_type=0, price=b[4])
        box_v = float(box.getVolume())
        box_w = float(box.max_weight)
        if box_v < ie_v or box_w < ie_w:
            continue
        # 3.1 尝试装箱
        heaps, pack_result = test2.packing([box], items, radius1, radius2, pre_packing_cubes=pre_packing_cubes)
        # 3.2 判断装箱是否成功
        if len(pack_result.bins[0].items) == pack_result.total_items:
            suc_num += 1
            # 3.3 计算空间利用率、载重利用率等信息
            space_ratio = ie_v / box_v
            weight_ratio = ie_w / box_w
            car_type = f"car{index}-{[a / 1000 for a in cars[index][0:3]]}"
            # 3.4 结果汇总
            results.append({
                'status': True,
                'bin_type': [car_type],
                'bin_num': [1],
                'space_ratio': space_ratio,
                'box_weight': box_w,
                'goods_weight': ie_w,
                'weight_ratio': weight_ratio,
                'price': b[4],
                'goods_volume': ie_v / 100 / 100 / 100,
                'bin_volume': box_v / 100 / 100 / 100,
                'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                'car-num': 1
            })
            # 3.5 结果保存
            with open(f'{path_to_result}/{token}.json', 'w') as fp:
                json.dump({
                    'ts': int(time.time()),
                    'finished': False,
                    'result': results
                }, fp, ensure_ascii=False)

    # 4. 计算多车方案
    car_types = []      # 记录方案是否已经计算
    multi_cars = [[[car]] for car in cars]
    finished = False
    while not finished:
        # 4.1 生成方案
        print('*' * 30)
        print(f"开始生成{len(multi_cars[0][0]) + 1}车方案")
        print('*' * 30)
        for cars_index in range(len(multi_cars)):
            current_cars = multi_cars[cars_index]
            cars_temp = []
            for current_car in current_cars:
                for car_index, car in enumerate(cars):
                    if car_index > cars_index:
                        continue
                    cars_temp.append(current_car + [car])
            multi_cars[cars_index] = cars_temp

        # 4.2 方案排序
        multi_boxes = [car for c_cars in multi_cars for car in c_cars]
        multi_boxes = sorted(multi_boxes, key=lambda x: sum([c[4] for c in x]), reverse=True)

        # 4.3 计算方案
        print('*' * 30)
        print(f"开始计算{len(multi_cars[0][0])}车方案")
        print('*' * 30)
        current_suc, current_total = 0, 0
        for boxes_index, boxes in enumerate(multi_boxes):
            bin_v = sum([be[0] * be[1] * be[2] for be in boxes])
            bin_w = sum([be[3] for be in boxes])
            if bin_v < ie_v or bin_w < ie_w:
                continue
            current_total += 1
            # 4.4 尝试装箱
            heaps, pack_result = test2.packing(boxes, items, radius1, radius2, pre_packing_cubes=pre_packing_cubes)
            bin_type, bin_num = [], []
            car_type = []
            for bi in pack_result.bins:
                bin_type.append(
                    f"car-{str([float(bi.width) / 1000, float(bi.height) / 1000, float(bi.depth) / 1000])}")
                car_type.append(str(bi.width))
                bin_num.append(1)
            car_type = sorted(car_type, key=lambda x: x)
            car_type = ','.join(car_type)
            if car_type not in car_types:
                # 4.5 判断装箱是否成功
                status = sum([len(ie.items) for ie in pack_result.bins]) == pack_result.total_items
                if status:
                    current_suc += 1
                    # 4.6 计算空间利用率、载重利用率等信息
                    space_ratio = ie_v / bin_v
                    weight_ratio = ie_w / bin_w
                    suc_num += 1
                    print('成功！！！', car_type)
                    # 4.7 追加结果
                    car_types.append(car_type)
                    results.append({
                        'status': True,
                        'bin_type': bin_type,
                        'bin_num': bin_num,
                        'space_ratio': space_ratio,
                        'box_weight': bin_w,
                        'goods_weight': ie_w,
                        'weight_ratio': weight_ratio,
                        'price': sum([bi.price for bi in pack_result.bins]),
                        'goods_volume': ie_v / 100 / 100 / 100,
                        'bin_volume': bin_v / 100 / 100 / 100,
                        'color': {},
                        'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                        'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                        'car-num': len(bin_type)
                    })
                    # 4.8 结果保存
                    with open(f'{path_to_result}/{token}.json', 'w') as fp:
                        json.dump({
                            'ts': int(time.time()),
                            'finished': False,
                            'result': results
                        }, fp, ensure_ascii=False)
                    if suc_num >= top_num:
                        finished = True

                else:
                    if current_suc / current_total < parser.parse_args().finishRatio and \
                            current_total > parser.parse_args().finishNum:
                        break
            else:
                pass
                # print('重复')

    if finished:
        print('装箱进程结束！！！')
    # 5. 更改结果状态
    with open(f'{path_to_result}/{token}.json', 'r') as fp:
        data = json.load(fp)
        data['finished'] = True
    with open(f'{path_to_result}/{token}.json', 'w') as fp:
        json.dump(data, fp, ensure_ascii=False)

    # 6. 日志
    end = time.time()
    print(f"装箱耗时{round(end - start, 3)}秒")
    log_content = {
        'url': '/pack',
        'user_ip': user_ip,
        'start_time': int(start),
        'time': round(end - start, 3),
        'goods': params['items'],
        'cars': params['cars'],
        'config': params.get('config_parameters', []),
        'result': results
    }
    with open(parser.parse_args().logPath, 'a') as fp:
        fp.write(json.dumps(log_content, ensure_ascii=False) + '\n')


def packing_items_2(params, token, user_ip='127.0.0.1', pre_packing_cubes=True, pre_min_num=20, top_num=5):
    # 0. 结果存储准备
    path_to_result = parser.parse_args().sessionPath
    if not os.path.exists(f'{path_to_result}/{token}.json'):
        with open(f'{path_to_result}/{token}.json', 'w') as fp:
            json.dump({
                'finished': False,
                'result': []
            }, fp)

    # 1. 解析参数
    items = params.get('items', [])
    config_parameters = params.get('config_parameters', [])

    if sum([ie[4] for ie in items]) < pre_min_num:
        pre_packing_cubes = False
    radius1 = int(config_parameters['dish']['second_dish_radius_1']) / 100
    radius2 = int(config_parameters['dish']['second_dish_radius_2']) / 100
    all_cars = params['cars']
    cars = [(car['size'][0], car['size'][1], car['size'][2], car['loadbear'], car['price']) for car in all_cars]
    cars = sorted(cars, key=lambda x: x[4], reverse=True)
    # 计算货物总体积、总重量
    ie_v, ie_w = 0, 0
    for ie in items:
        ie_w += ie[3] * ie[4]
        ie_v += ie[0] * ie[1] * ie[2] * ie[4]

    results = []
    # 2. 计算单车方案
    all_heaps, all_packers, all_goods_nums = [], [], []
    for index, car in enumerate(cars):
        box = Bin(f"car-{index}", (car[0], car[1], car[2]), car[3], 0, put_type=0, price=car[4])
        # 2.1 尝试计算装箱方案
        heaps, packer = test2.packing([box], items, radius1, radius2, pre_packing_cubes=pre_packing_cubes)
        all_heaps.append(heaps)
        all_goods_nums.append(packer.total_items)
        all_packers.append([packer])
        # 判断该方案是否成功
        if packer.total_items == len(packer.bins[0].items):
            # 2.2 计算空间利用率、载重利用率等信息
            b = packer.bins[0]
            space_ratio = ie_v / float(b.width * b.height * b.depth)
            weight_ratio = ie_w / float(b.max_weight)
            car_type = f"car{index}-{[a / 1000 for a in car[0:3]]}"
            # 2.3 结果汇总
            results.append({
                'status': True,
                'bin_type': [car_type],
                'bin_num': [1],
                'space_ratio': space_ratio,
                'box_weight': float(b.max_weight),
                'goods_weight': ie_w,
                'weight_ratio': weight_ratio,
                'price': car[4],
                'goods_volume': ie_v,
                'bin_volume': float(b.width * b.height * b.depth),
                'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                'packer': str(pickle.dumps(packer), encoding='latin1'),
                'car-num': 1
            })
            # 2.4 结果保存
            with open(f'{path_to_result}/{token}.json', 'w') as fp:
                json.dump(results, fp)

    # 3. 计算多车方案
    while True:
        print('#' * 30)
        print(f"开始计算{len(all_packers[0][0].bins) + 1}车方案")
        fa_start = time.time()
        for packers_index in range(len(all_packers)):
            packers = all_packers[packers_index]
            packers_temp = []
            for packer in packers:
                for car_index, car in enumerate(cars):
                    if car_index > packers_index:
                        continue
                    # 3.1 重置packer状态
                    box = Bin(f"car-{index}", (car[0], car[1], car[2]), car[3], 0, put_type=0, price=car[4])
                    packer_temp = copy.deepcopy(packer)
                    packer_temp.items = packer_temp.bins[0].unfitted_items
                    for b in packer_temp.bins:
                        b.is_over = True
                    # 3.2 添加当前的车厢
                    packer_temp.addBin(box)
                    # 3.3 尝试计算
                    packer_temp.pack(bigger_first=False,
                                     distribute_items=False,
                                     fix_point=True,
                                     check_stable=True,
                                     support_surface_ratio=1.,
                                     number_of_decimals=2)
                    # 3.4 判断该方案是否成功
                    if sum([len(b.items) for b in packer_temp.bins]) == all_goods_nums[packers_index]:
                        print('装箱成功')
                        # 3.5 计算空间利用率、载重利用率等信息
                        bin_v = sum([float(b.width * b.height * b.depth) for b in packer_temp.bins])
                        bin_w = sum([float(b.max_weight) for b in packer_temp.bins])
                        space_ratio = ie_v / bin_v
                        weight_ratio = ie_w / bin_w
                        price = sum([b.price for b in packer_temp.bins])
                        bin_type, bin_num = [], []
                        for bi in packer_temp.bins:
                            bin_type.append(
                                f"car-{str([float(bi.width) / 1000, float(bi.height) / 1000, float(bi.depth) / 1000])}")
                            bin_num.append(1)
                        # 3.6 结果更新
                        results.append({
                            'status': True,
                            'bin_type': bin_type,
                            'bin_num': bin_num,
                            'space_ratio': space_ratio,
                            'box_weight': bin_w,
                            'goods_weight': ie_w,
                            'weight_ratio': weight_ratio,
                            'price': price,
                            'goods_volume': ie_v,
                            'bin_volume': bin_v,
                            'color': {},
                            'heaps': str(pickle.dumps(all_heaps[packers_index]), encoding='latin1'),
                            'packer': str(pickle.dumps(packer_temp), encoding='latin1'),
                            'car-num': len(packer_temp.bins)
                        })
                        # 3.7 结果保存
                        with open(f'{path_to_result}/{token}.json', 'w') as fp:
                            json.dump(results, fp)
                    packers_temp.append(packer_temp)
            all_packers[packers_index] = packers_temp
        print(f"耗时{round(time.time() - fa_start, 3)}秒")
        print('#' * 30)


# 绘图接口，对装箱结果进行绘图
# @app.route('/plot', methods=['POST'])
def plot(imgPath, delImg, plotHeapCube, logPath, heaps, packer, param_start, param_end, plot_type, result_plot, user_ip):
    # 获取参数
    matplot_start = time.time()
    angles = [
        {
            'elev': 10,  # 仰角
            'azim': 180,  # 方位角
        },
        {
            'elev': 30,  # 仰角
            'azim': 60,  # 方位角
        },
        {
            'elev': 60,  # 仰角
            'azim': 120,  # 方位角
        },
        {
            'elev': 90,  # 仰角
            'azim': 180,  # 方位角
        }
    ]
    # 1. 使用matplotlib绘图
    pic_root = imgPath
    base64 = []
    base64_map = {f"{i + 1}-{float(b.width) / 1000}x{float(b.height) / 1000}x{float(b.depth) / 1000}": [] for i, b in
                  enumerate(packer.bins)}

    for i, b in enumerate(packer.bins):

        bin_size = f"{i + 1}-{float(b.width) / 1000}x{float(b.height) / 1000}x{float(b.depth) / 1000}"

        for index, angle in enumerate(angles):
            # 1.1 绘图
            elev, azim = angle['elev'], angle['azim']
            # p, fig = test2.plot_heaps_matplot(b, heaps, f"elevation: {elev}°, azimuth: {azim}°", elev=elev, azim=azim, plot_type=params.get('figure_type', 1))
            p, fig = test2.plot_heaps_matplot(b, heaps, '', elev=elev, azim=azim,
                                              plot_heap_cube=plotHeapCube,
                                              plot_type=plot_type)

            # 1.2 生成文件名
            ts = int(time.time() * 1000)
            pic_name = f"{ts}{index}{random.randint(-100, 100)}"
            pic_name = md5_encode(pic_name)

            # 1.3 保存文件
            fig.savefig(f"{pic_root}/{pic_name}.png")


            # 1.4 转base64
            bs64 = image_to_base64(f"{pic_root}/{pic_name}.png")
            base64.append(bs64)
            base64_map[bin_size].append(bs64)
            p.close()

            # 1.5 删除本地图片
            # print(pic_root, parser.parse_args().delImg)
            if delImg:
                os.remove(f"{pic_root}/{pic_name}.png")
    matplot_end = time.time()

    # 2. 使用plotly绘图
    plotly_start = time.time()
    plotly_end = time.time()
    log_content = {
        'url': '/plot',
        'user_ip': user_ip,
        'start_time': int(param_start),
        'get_param_time': round(param_end - param_start, 3),
        'matplotlib_time': round(matplot_end - matplot_start, 3),
        'plotly_time': round(plotly_end - plotly_start, 3),
        'heaps': heaps,
        'packer': packer
    }

    # with open(logPath, 'a') as fp:
    #     fp.write(f"{json.dumps(log_content, ensure_ascii=False)}\n")

    # 2.4 结果保存
    with open(f'{result_plot}', 'w') as fp:
        json.dump({'base64': base64, 'car_image': base64_map}, fp)

    return {'base64': base64, 'car_image': base64_map}


def str2bool(v):
    if isinstance(v, bool):
        return v
    if v.lower() in ('yes', 'true', 'True', 't', 'y', '1'):
        return True
    elif v.lower() in ('no', 'false', 'False', 'f', 'n', '0'):
        return False
    else:
        raise argparse.ArgumentTypeError('Boolean value expected.')


# class BoxPloting(object):
#     def __init__(self, imgPath, delImg, plotHeapCube, logPath, heaps, packer, param_start, param_end, plot_type, result_plot, user_ip):
#         self.imgPath = imgPath
#         self.delImg = delImg
#         self.plotHeapCube = plotHeapCube
#         self.imgPath =


if __name__ == '__main__':
    # parser.add_argument('--port', type=int, default=13111, help='端口号')
    parser.add_argument('--heaps', type=str, default='./heaps/f92bdd94f7ee70ca025dad668d8e080c_heaps.json', help='heaps')
    parser.add_argument('--packer', type=str, default='./packer/f92bdd94f7ee70ca025dad668d8e080c_packer.txt', help='packer')
    parser.add_argument('--use_plotly', type=bool, default=False, help='plot_type')
    parser.add_argument('--plot_type', type=int, default=1, help='plot_type')
    parser.add_argument('--result_plot', type=str, default='./result_plot/f92bdd94f7ee70ca025dad668d8e080c_result.json', help='result_plot')
    parser.add_argument('--user_ip', type=str, default='', help='user_ip')


    parser.add_argument('--imgPath', type=str, default='./front/images', help='图片保存路径')
    parser.add_argument('--delImg', type=str2bool, default=True, help='是否在磁盘上删除图片')
    parser.add_argument('--plotHeapCube', type=str2bool, default=False, help='是否绘制heap的外边框')
    parser.add_argument('--logPath', type=str, default='./pack.log', help='日志文件路径')


    args = parser.parse_args()

    if not os.path.exists(args.imgPath):
        os.makedirs(args.imgPath)

    param_start = time.time()
    heaps = json.load(open(args.heaps, 'r'))
    with open(args.packer, 'rb') as file:
        packer = pickle.load(file)
    param_end = time.time()

    imgPath = args.imgPath
    delImg = args.delImg
    plotHeapCube = args.plotHeapCube
    logPath = args.logPath

    use_plotly = args.use_plotly
    plot_type = args.plot_type
    result_plot = args.result_plot
    user_ip = args.user_ip

    # app.run(host='0.0.0.0', port=args.port, debug=parser.parse_args().debug)
    plot(imgPath, delImg, plotHeapCube, logPath, heaps, packer, param_start, param_end, plot_type, result_plot, user_ip)
